package design.pattern.Lu10ChainResponsibilityPattern;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Date;

/**
 * @program JavaBase
 * @description: 责任链模式：模拟企业微信审批机制
 *  - 本案例体现出：责任链模式、构造器模式、模版方法、代理模式
 * @author: zhanglu
 * @create: 2022-05-17 14:51:00
 */
@Slf4j
public class ChainResponsibilityPattern03 {

    //最大审批等级(可以动态变化)
    public final Integer MAX_LEVEL = 3;

    /********************数据模型********************/

    //审批人
    @Data
    static class Approver{
        private Long userId;
        private String userName;
        //审批人角色
        private Role role;
    }

    @Getter
    @AllArgsConstructor
    public enum Role{
        TECHNOLOGY_DEPT_MANAGER(1, "技术部门经理"),
        OPERATE_DEPT_MANAGER(1, "运营部门经理"),
        PROJECT_MANAGER(2, "项目经理"),
        FUNCTION_MANAGER(2, "职能经理"),
        TECHNOLOGY_MANAGER(2, "技术经理"),
        DBA(3, "dba"),
        DEV_LEAD(3, "开发组长")
        ;
        private Integer level;
        private String description;
    }

    //申请
    @Data
    static class Apply{
        private Long id;
        //申请发起时间
        private Date createTime;
        //申请更新时间
        private Date updateTime;
        //申请有效审核时间 (超过有效期自动结束)
        private Date validExamineTime;
        //审批状态
        private Integer status;
        private String statusStr;
        //申请内容
        private String description;
    }

    /********************责任链********************/

    interface AuthInterface{
        Apply doAuth(Apply apply);
    }

    static abstract class AuthLink implements AuthInterface{
        private Approver approver;
        private AuthLink next;
        private AuthLink(Approver approver){
            this.approver = approver;
        }
        public AuthLink appendAuthLink(AuthLink next){
            this.next = next;
            return this;
        }
        public Approver getApprover(){
            return approver;
        }
        public AuthLink getNext(){
            return next;
        }

        //模版方法
        protected void update(Apply apply){
            apply.setUpdateTime(new Date());
            apply.setStatusStr(apply.getStatusStr() + " ---> " + StrUtil.format("[审批人：{} - 角色等级({})：{}]",
                    this.getApprover().getUserName(),
                    this.getApprover().getRole().getLevel(),
                    this.getApprover().getRole().getDescription()));
            apply.setStatus(apply.getStatus() + 1);
        }
    }

    static class Auth extends AuthLink{
        public Auth(Approver approver) {
            super(approver);
        }
        @Override
        public Apply doAuth(Apply apply) {
            //审批逻辑
            this.update(apply);
            AuthLink next = super.getNext();
            if(next == null){
                return apply;
            }
            return next.doAuth(apply);
        }
    }

    /********************代理********************/
    static class AuthProxy implements AuthInterface{

        @Override
        public Apply doAuth(Apply apply) {
            return null;
        }

    }

    /********************测试********************/

    @Test
    public void test01(){
        Approver approver01 = new Approver();
        approver01.setUserId(1L);
        approver01.setUserName("张三");
        approver01.setRole(Role.TECHNOLOGY_DEPT_MANAGER);
        Approver approver02 = new Approver();
        approver02.setUserId(2L);
        approver02.setUserName("李四");
        approver02.setRole(Role.PROJECT_MANAGER);
        Approver approver03 = new Approver();
        approver03.setUserId(3L);
        approver03.setUserName("王二");
        approver03.setRole(Role.DEV_LEAD);
        //创建责任链(体现出：建造者模式)
        AuthInterface authLink = new Auth(approver01).appendAuthLink(new Auth(approver02).appendAuthLink(new Auth(approver03)));
        //申请单
        Apply apply = new Apply();
        apply.setId(1L);
        apply.setCreateTime(new Date());
        apply.setUpdateTime(new Date());
        apply.setValidExamineTime(new Date());
        apply.setStatus(0);
        apply.setStatusStr("");
        apply.setDescription("线上数据库读权限-运营导数据");
        //动态代理-记录审批结果日志
        InvocationHandler dynamicProxy = (proxy, method, args) -> {
            Object res = method.invoke(authLink, args);
            System.out.println("执行结果：" + JSON.toJSONString(res));
            return res;
        };
        AuthInterface authInterface = (AuthInterface) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{AuthInterface.class}, dynamicProxy);
        Apply res = authInterface.doAuth(apply);
    }

}
